package zy.service.money.expense.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import zy.dao.approve.ApproveRecordDAO;
import zy.dao.base.shop.ShopDAO;
import zy.dao.money.bank.BankDAO;
import zy.dao.money.bank.BankRunDAO;
import zy.dao.money.expense.ExpenseDAO;
import zy.dao.sys.print.PrintDAO;
import zy.dto.money.expense.ExpenseReportDepartmentDto;
import zy.dto.money.expense.ExpenseReportDto;
import zy.dto.money.expense.ExpenseReportMonthDto;
import zy.entity.PageData;
import zy.entity.PageInfo;
import zy.entity.approve.T_Approve_Record;
import zy.entity.money.bank.T_Money_Bank;
import zy.entity.money.bank.T_Money_BankRun;
import zy.entity.money.expense.T_Money_Expense;
import zy.entity.money.expense.T_Money_ExpenseList;
import zy.entity.sys.user.T_Sys_User;
import zy.service.money.expense.ExpenseService;
import zy.util.CommonUtil;
import zy.util.DateUtil;
import zy.util.StringUtil;

@Service
public class ExpenseServiceImpl implements ExpenseService{
	@Resource
	private ExpenseDAO expenseDAO;
	@Resource
	private ApproveRecordDAO approveRecordDAO;
	@Resource
	private BankDAO bankDAO;
	@Resource
	private BankRunDAO bankRunDAO;
	@Resource
	private ShopDAO shopDAO;
	@Resource
	private PrintDAO printDAO;
	
	@Override
	public PageData<T_Money_Expense> page(Map<String, Object> params) {
		Integer pageSize = (Integer)params.get(CommonUtil.PAGESIZE);
		Integer pageIndex = (Integer)params.get(CommonUtil.PAGEINDEX);
		
		Integer totalCount = expenseDAO.count(params);
		PageInfo pageInfo = new PageInfo(totalCount, pageSize, pageIndex);
		params.put(CommonUtil.START, (pageIndex-1)*pageSize);
		params.put(CommonUtil.END, pageSize);
		
		List<T_Money_Expense> list = expenseDAO.list(params);
		PageData<T_Money_Expense> pageData = new PageData<T_Money_Expense>();
		pageData.setPageInfo(pageInfo);
		pageData.setList(list);
		return pageData;
	}

	@Override
	public T_Money_Expense load(Integer ep_id) {
		T_Money_Expense expense = expenseDAO.load(ep_id);
		if(expense != null){
			T_Approve_Record approve_Record = approveRecordDAO.load(expense.getEp_number(), expense.getCompanyid());
			if(approve_Record != null){
				expense.setAr_describe(approve_Record.getAr_describe());
			}
		}
		return expense;
	}
	
	@Override
	public T_Money_Expense load(String number,Integer companyid) {
		return expenseDAO.load(number, companyid);
	}
	
	@Override
	public List<T_Money_ExpenseList> temp_list(Map<String, Object> params) {
		return expenseDAO.temp_list(params);
	}

	@Override
	@Transactional
	public void temp_save(List<T_Money_ExpenseList> temps, T_Sys_User user) {
		if (temps == null || temps.size() == 0) {
			throw new RuntimeException("请选择费用类型");
		}
		List<String> existCode = expenseDAO.temp_check(user.getUs_id(),user.getCompanyid());
		List<T_Money_ExpenseList> temps_add = new ArrayList<T_Money_ExpenseList>();
		for (T_Money_ExpenseList temp : temps) {
			if(!existCode.contains(temp.getEpl_mp_code())){
				temp.setEpl_sharemonth(1);
				temp.setEpl_us_id(user.getUs_id());
				temp.setEpl_remark("");
				temp.setCompanyid(user.getCompanyid());
				temps_add.add(temp);
			}
		}
		if (temps_add.size() > 0) {
			expenseDAO.temp_save(temps_add);
		}
	}

	@Override
	@Transactional
	public void temp_updateMoney(T_Money_ExpenseList temp) {
		expenseDAO.temp_updateMoney(temp);
	}
	
	@Override
	@Transactional
	public void temp_updateSharemonth(T_Money_ExpenseList temp) {
		expenseDAO.temp_updateSharemonth(temp);
	}

	@Override
	@Transactional
	public void temp_updateRemark(T_Money_ExpenseList temp) {
		temp.setEpl_remark(StringUtil.decodeString(temp.getEpl_remark()));
		expenseDAO.temp_updateRemark(temp);
	}

	@Override
	public void temp_del(Integer epl_id) {
		expenseDAO.temp_del(epl_id);
	}

	@Override
	public void temp_clear(Integer us_id, Integer companyid) {
		expenseDAO.temp_clear(us_id, companyid);
	}

	@Override
	public List<T_Money_ExpenseList> detail_list(Map<String, Object> params) {
		return expenseDAO.detail_list(params);
	}
	
	@Override
	@Transactional
	public void save(T_Money_Expense expense, T_Sys_User user) {
		if(expense == null){
			throw new IllegalArgumentException("参数不能为null");
		}
		if(StringUtil.isEmpty(expense.getEp_shop_code())){
			throw new IllegalArgumentException("店铺名称不能为空");
		}
		if(StringUtil.isEmpty(expense.getEp_manager())){
			throw new IllegalArgumentException("经办人不能为空");
		}
		if(StringUtil.isEmpty(expense.getEp_ba_code())){
			throw new IllegalArgumentException("银行账户不能为空");
		}
		expense.setCompanyid(user.getCompanyid());
		expense.setEp_us_id(user.getUs_id());
		expense.setEp_maker(user.getUs_name());
		expense.setEp_ar_state(CommonUtil.AR_STATE_NOTAPPROVE);
		expense.setEp_sysdate(DateUtil.getCurrentTime());
		//1.查临时表
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("epl_us_id", user.getUs_id());
		params.put("companyid", user.getCompanyid());
		List<T_Money_ExpenseList> temps = expenseDAO.temp_list(params);
		if(temps == null || temps.size() == 0){
			throw new RuntimeException("单据已保存，请勿重复提交");
		}
		//2.保存单据
		double ep_money = 0d;
		for (T_Money_ExpenseList temp : temps) {
			if(temp.getEpl_money().doubleValue() == 0d){
				throw new RuntimeException("明细数据存在为0的费用类型，请修改");
			}
			ep_money += temp.getEpl_money();
		}
		expense.setEp_money(ep_money);
		
		
		List<T_Money_ExpenseList> temps_save = new ArrayList<T_Money_ExpenseList>();
		List<String> monthDate = null;
		for (T_Money_ExpenseList temp : temps) {
			if (expense.getEp_share().intValue() == 1 && temp.getEpl_sharemonth() > 1) {//分摊
				try {
					monthDate = DateUtil.getShareMonthDate(expense.getEp_date(), temp.getEpl_sharemonth());
				} catch (Exception e) {
					throw new RuntimeException("单据保存失败");
				}
				Double avgMoney = Double.parseDouble(String.format("%.2f", temp.getEpl_money()/temp.getEpl_sharemonth()));
				Double lastMoney = temp.getEpl_money() - avgMoney * (temp.getEpl_sharemonth() - 1);
				for (int i = 0; i < temp.getEpl_sharemonth(); i++) {
					T_Money_ExpenseList item = new T_Money_ExpenseList();
					item.setEpl_mp_code(temp.getEpl_mp_code());
					item.setEpl_remark(temp.getEpl_remark());
					item.setEpl_sharedate(monthDate.get(i));
					item.setCompanyid(temp.getCompanyid());
					if (i == temp.getEpl_sharemonth() - 1) {//最后一个
						item.setEpl_money(lastMoney);
					}else {
						item.setEpl_money(avgMoney);
					}
					temps_save.add(item);
				}
			}else {//不分摊
				temp.setEpl_sharedate(expense.getEp_date());
				temps_save.add(temp);
			}
		}
		expenseDAO.save(expense, temps_save);
		//3.删除临时表
		expenseDAO.temp_clear(user.getUs_id(), user.getCompanyid());
	}
	
	@Override
	@Transactional
	public void update(T_Money_Expense expense, T_Sys_User user) {
		if(expense == null){
			throw new IllegalArgumentException("参数不能为null");
		}
		if(StringUtil.isEmpty(expense.getEp_shop_code())){
			throw new IllegalArgumentException("店铺名称不能为空");
		}
		if(StringUtil.isEmpty(expense.getEp_manager())){
			throw new IllegalArgumentException("经办人不能为空");
		}
		if(StringUtil.isEmpty(expense.getEp_ba_code())){
			throw new IllegalArgumentException("银行账户不能为空");
		}
		expense.setCompanyid(user.getCompanyid());
		expense.setEp_us_id(user.getUs_id());
		expense.setEp_maker(user.getUs_name());
		expense.setEp_ar_state(CommonUtil.AR_STATE_NOTAPPROVE);
		expense.setEp_sysdate(DateUtil.getCurrentTime());
		//1.查临时表
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("epl_us_id", user.getUs_id());
		params.put("companyid", user.getCompanyid());
		List<T_Money_ExpenseList> temps = expenseDAO.temp_list(params);
		if(temps == null || temps.size() == 0){
			throw new RuntimeException("单据已保存，请勿重复提交");
		}
		//1.2验证单据
		T_Money_Expense oldExpense = expenseDAO.check(expense.getEp_number(), user.getCompanyid());
		if (oldExpense == null || !CommonUtil.AR_STATE_FAIL.equals(oldExpense.getEp_ar_state())) {
			throw new RuntimeException("单据已修改，请勿重复提交");
		}
		//2.保存单据
		double ep_money = 0d;
		for (T_Money_ExpenseList temp : temps) {
			if(temp.getEpl_money().doubleValue() == 0d){
				throw new RuntimeException("明细数据存在为0的费用类型，请修改");
			}
			ep_money += temp.getEpl_money();
		}
		expense.setEp_money(ep_money);
		
		List<T_Money_ExpenseList> temps_save = new ArrayList<T_Money_ExpenseList>();
		List<String> monthDate = null;
		for (T_Money_ExpenseList temp : temps) {
			if (expense.getEp_share().intValue() == 1 && temp.getEpl_sharemonth() > 1) {//分摊
				try {
					monthDate = DateUtil.getShareMonthDate(expense.getEp_date(), temp.getEpl_sharemonth());
				} catch (Exception e) {
					throw new RuntimeException("单据保存失败");
				}
				Double avgMoney = Double.parseDouble(String.format("%.2f", temp.getEpl_money()/temp.getEpl_sharemonth()));
				Double lastMoney = temp.getEpl_money() - avgMoney * (temp.getEpl_sharemonth() - 1);
				for (int i = 0; i < temp.getEpl_sharemonth(); i++) {
					T_Money_ExpenseList item = new T_Money_ExpenseList();
					item.setEpl_mp_code(temp.getEpl_mp_code());
					item.setEpl_remark(temp.getEpl_remark());
					item.setEpl_sharedate(monthDate.get(i));
					item.setCompanyid(temp.getCompanyid());
					if (i == temp.getEpl_sharemonth() - 1) {//最后一个
						item.setEpl_money(lastMoney);
					}else {
						item.setEpl_money(avgMoney);
					}
					temps_save.add(item);
				}
			}else {//不分摊
				temp.setEpl_sharedate(expense.getEp_date());
				temps_save.add(temp);
			}
		}
		expenseDAO.deleteList(expense.getEp_number(), user.getCompanyid());
		expenseDAO.update(expense, temps_save);
		//3.删除临时表
		expenseDAO.temp_clear(user.getUs_id(), user.getCompanyid());
	}
	
	@Override
	@Transactional
	public void approveBatch(String numbers, T_Approve_Record record, T_Sys_User user) {
		Assert.hasText(numbers,"参数number不能为null");
		List<String> numberList = Arrays.asList(numbers.split(","));
		List<T_Money_Expense> expenses = expenseDAO.check(numberList, user.getCompanyid());
		Assert.notEmpty(expenses,"单据不存在");
		for (T_Money_Expense item : expenses) {
			if(!CommonUtil.AR_STATE_NOTAPPROVE.equals(item.getEp_ar_state())){
				throw new RuntimeException("存在单据已经审核不能重复操作");
			}
			item.setEp_ar_state(record.getAr_state());
			item.setEp_ar_date(DateUtil.getCurrentTime());
		}
		expenseDAO.updateApprove(expenses);
		//保存审核记录表
		List<T_Approve_Record> records = new ArrayList<T_Approve_Record>();
		for (T_Money_Expense item : expenses) {
			T_Approve_Record itemRecord = new T_Approve_Record();
			itemRecord.setAr_number(item.getEp_number());
			itemRecord.setAr_state(record.getAr_state());
			itemRecord.setAr_describe(record.getAr_describe());
			itemRecord.setAr_sysdate(DateUtil.getCurrentTime());
			itemRecord.setAr_us_name(user.getUs_name());
			itemRecord.setAr_type("t_money_expense");
			itemRecord.setCompanyid(user.getCompanyid());
			records.add(itemRecord);
		}
		approveRecordDAO.save(records);
		if(!CommonUtil.AR_STATE_APPROVED.equals(record.getAr_state())){//审核不通过，则直接返回
			return;
		}
		//3.审核通过:银行账目及流水
		List<T_Money_BankRun> bankRuns = new ArrayList<T_Money_BankRun>();
		for (T_Money_Expense item : expenses) {
			T_Money_Bank bank = bankDAO.queryByCode(item.getEp_ba_code(), user.getCompanyid());
			bank.setBa_balance(bank.getBa_balance() - item.getEp_money());
			bankDAO.updateBalanceById(bank);
			T_Money_BankRun bankRun = new T_Money_BankRun();
			bankRun.setBr_ba_code(item.getEp_ba_code());
			bankRun.setBr_balance(bank.getBa_balance());
			bankRun.setBr_bt_code(CommonUtil.BANKRUN_MONEY_EXPENSE);
			bankRun.setBr_date(DateUtil.getCurrentTime());
			bankRun.setBr_out(item.getEp_money());
			bankRun.setBr_manager(item.getEp_manager());
			bankRun.setBr_number(item.getEp_number());
			bankRun.setBr_remark(item.getEp_remark());
			bankRun.setBr_shop_code(bank.getBa_shop_code());
			bankRun.setBr_sysdate(DateUtil.getCurrentTime());
			bankRun.setCompanyid(user.getCompanyid());
			bankRuns.add(bankRun);
		}
		bankRunDAO.save(bankRuns);
	}
	
	@Override
	@Transactional
	public T_Money_Expense approve(String number, T_Approve_Record record, T_Sys_User user) {
		Assert.hasText(number,"参数number不能为null");
		T_Money_Expense expense = expenseDAO.check(number, user.getCompanyid());
		Assert.notNull(expense,"单据不存在");
		if(!CommonUtil.AR_STATE_NOTAPPROVE.equals(expense.getEp_ar_state())){
			throw new RuntimeException("单据已经审核");
		}
		//更新单据审核状态
		expense.setEp_ar_state(record.getAr_state());
		expense.setEp_ar_date(DateUtil.getCurrentTime());
		expenseDAO.updateApprove(expense);
		//保存审核记录表
		record.setAr_number(number);
		record.setAr_sysdate(DateUtil.getCurrentTime());
		record.setAr_us_name(user.getUs_name());
		record.setAr_type("t_money_expense");
		record.setCompanyid(user.getCompanyid());
		approveRecordDAO.save(record);
		if(!CommonUtil.AR_STATE_APPROVED.equals(expense.getEp_ar_state())){//审核不通过，则直接返回
			return expense;
		}
		//3.审核通过:银行账目及流水
		T_Money_Bank bank = bankDAO.queryByCode(expense.getEp_ba_code(), user.getCompanyid());
		bank.setBa_balance(bank.getBa_balance() - expense.getEp_money());
		bankDAO.updateBalanceById(bank);
		T_Money_BankRun bankRun = new T_Money_BankRun();
		bankRun.setBr_ba_code(expense.getEp_ba_code());
		bankRun.setBr_balance(bank.getBa_balance());
		bankRun.setBr_bt_code(CommonUtil.BANKRUN_MONEY_EXPENSE);
		bankRun.setBr_date(DateUtil.getCurrentTime());
		bankRun.setBr_out(expense.getEp_money());
		bankRun.setBr_manager(expense.getEp_manager());
		bankRun.setBr_number(expense.getEp_number());
		bankRun.setBr_remark(expense.getEp_remark());
		bankRun.setBr_shop_code(bank.getBa_shop_code());
		bankRun.setBr_sysdate(DateUtil.getCurrentTime());
		bankRun.setCompanyid(user.getCompanyid());
		bankRunDAO.save(bankRun);
		return expense;
	}
	
	@Override
	@Transactional
	public T_Money_Expense reverse(String number, T_Sys_User user) {
		Assert.hasText(number,"参数number不能为null");
		T_Money_Expense expense = expenseDAO.check(number, user.getCompanyid());
		Assert.notNull(expense,"单据不存在");
		if(!CommonUtil.AR_STATE_APPROVED.equals(expense.getEp_ar_state())){
			throw new RuntimeException("单据未审核或审核未通过");
		}
		//1.更新单据审核状态
		expense.setEp_ar_state(CommonUtil.AR_STATE_NOTAPPROVE);
		expense.setEp_ar_date(DateUtil.getCurrentTime());
		expenseDAO.updateApprove(expense);
		//2.保存审核记录表
		T_Approve_Record record = new T_Approve_Record();
		record.setAr_state(CommonUtil.AR_STATE_REVERSE_APPROVE);
		record.setAr_describe(user.getUs_name()+"反审核单据");
		record.setAr_number(number);
		record.setAr_sysdate(DateUtil.getCurrentTime());
		record.setAr_us_name(user.getUs_name());
		record.setAr_type("t_money_expense");
		record.setCompanyid(user.getCompanyid());
		approveRecordDAO.save(record);
		//3.反审核:银行账目及流水
		T_Money_Bank bank = bankDAO.queryByCode(expense.getEp_ba_code(), user.getCompanyid());
		bank.setBa_balance(bank.getBa_balance() + expense.getEp_money());
		bankDAO.updateBalanceById(bank);
		T_Money_BankRun bankRun = new T_Money_BankRun();
		bankRun.setBr_ba_code(expense.getEp_ba_code());
		bankRun.setBr_balance(bank.getBa_balance());
		bankRun.setBr_bt_code(CommonUtil.BANKRUN_MONEY_EXPENSE);
		bankRun.setBr_date(DateUtil.getCurrentTime());
		bankRun.setBr_enter(expense.getEp_money());
		bankRun.setBr_manager(expense.getEp_manager());
		bankRun.setBr_number(expense.getEp_number());
		bankRun.setBr_remark("反审核恢复账目");
		bankRun.setBr_shop_code(bank.getBa_shop_code());
		bankRun.setBr_sysdate(DateUtil.getCurrentTime());
		bankRun.setCompanyid(user.getCompanyid());
		bankRunDAO.save(bankRun);
		return expense;
	}
	
	@Override
	@Transactional
	public void initUpdate(String number, Integer us_id, Integer companyid) {
		List<T_Money_ExpenseList> details = expenseDAO.detail_list_forsavetemp(number, companyid);;
		for(T_Money_ExpenseList item:details){
			item.setEpl_us_id(us_id);
		}
		expenseDAO.temp_clear(us_id, companyid);
		expenseDAO.temp_save(details);
	}
	
	@Override
	@Transactional
	public void del(String numbers, Integer companyid) {
		Assert.hasText(numbers,"参数number不能为null");
		List<String> numberList = Arrays.asList(numbers.split(","));
		List<T_Money_Expense> expenses = expenseDAO.check(numberList, companyid);
		Assert.notEmpty(expenses,"单据不存在");
		for (T_Money_Expense item : expenses) {
			if(!CommonUtil.AR_STATE_NOTAPPROVE.equals(item.getEp_ar_state()) && !CommonUtil.AR_STATE_FAIL.equals(item.getEp_ar_state())){
				throw new RuntimeException("存在单据已审核通过不能删除！");
			}
		}
		expenseDAO.del(numberList, companyid);
	}
	
	@Override
	public Map<String, Object> loadPrintData(String number, Integer sp_id, T_Sys_User user) {
		Map<String, Object> resultMap = printDAO.loadPrint4Bill(sp_id);
		T_Money_Expense expense = expenseDAO.load(number, user.getCompanyid());
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("epl_number", number);
		params.put("companyid", user.getCompanyid());
		List<T_Money_ExpenseList> expenseList = expenseDAO.detail_list(params);
		resultMap.put("expense", expense);
		resultMap.put("expenseList", expenseList);
		resultMap.put("shop", shopDAO.load(expense.getEp_shop_code(), user.getCompanyid()));
		return resultMap;
	}
	
	@Override
	public List<ExpenseReportDto> listReport(Map<String, Object> params) {
		Object companyid = params.get(CommonUtil.COMPANYID);
		if (companyid == null) {
			throw new IllegalArgumentException("连接超时，请重新登录!");
		}
		return expenseDAO.listReport(params);
	}
	
	@Override
	public List<T_Money_ExpenseList> listReportDetail(Map<String, Object> params) {
		Object companyid = params.get(CommonUtil.COMPANYID);
		if (companyid == null) {
			throw new IllegalArgumentException("连接超时，请重新登录!");
		}
		return expenseDAO.listReportDetail(params);
	}
	
	@Override
	public List<ExpenseReportMonthDto> expense_head(Map<String, Object> params) {
		List<ExpenseReportMonthDto> resultDtos = new ArrayList<ExpenseReportMonthDto>();
		Map<String, ExpenseReportMonthDto> resultMap = expenseDAO.expense_head(params);
		ExpenseReportMonthDto dto;
		for (int i = 1; i <= 12; i++) {
			if(resultMap.containsKey(String.valueOf(i))){
				dto = resultMap.get(String.valueOf(i));
			}else {
				dto = new ExpenseReportMonthDto();
			}
			dto.setId(String.valueOf(i));
			dto.setMonth(String.format("%02d", i));
			dto.setGross_profit(dto.getBusiness_income()-dto.getBusiness_cost());
			dto.setNet_profit(dto.getGross_profit()-dto.getExpense());
			resultDtos.add(dto);
		}
		return resultDtos;
	}
	@Override
	public List<ExpenseReportMonthDto> expense_shop(Map<String, Object> params) {
		List<ExpenseReportMonthDto> resultDtos = new ArrayList<ExpenseReportMonthDto>();
		Map<String, ExpenseReportMonthDto> resultMap = expenseDAO.expense_shop(params);
		ExpenseReportMonthDto dto;
		for (int i = 1; i <= 12; i++) {
			if(resultMap.containsKey(String.valueOf(i))){
				dto = resultMap.get(String.valueOf(i));
			}else {
				dto = new ExpenseReportMonthDto();
			}
			dto.setId(String.valueOf(i));
			dto.setMonth(String.format("%02d", i));
			dto.setGross_profit(dto.getBusiness_income()-dto.getBusiness_cost());
			dto.setNet_profit(dto.getGross_profit()-dto.getExpense());
			resultDtos.add(dto);
		}
		return resultDtos;
	}
	
	@Override
	public List<ExpenseReportDepartmentDto> expense_department(Map<String, Object> params) {
		List<ExpenseReportDepartmentDto> list = expenseDAO.expense_department(params);
		for (ExpenseReportDepartmentDto dto : list) {
			String depart_money = dto.getDepart_money();
			if(StringUtil.isEmpty(depart_money)){
				continue;
			}
			String[] departMoneys = depart_money.split(",");
			for (String item : departMoneys) {
				String[] temps = item.split(":");
				if(temps.length == 2){
					dto.getMoneyMap().put(temps[0], Double.parseDouble(temps[1]));
				}
			}
		}
		return list;
	}
	
}
